package com.javatest.redpacket.service.impl;

import com.javatest.redpacket.dao.RedPacketDao;
import com.javatest.redpacket.dao.UserRedPacketDao;
import com.javatest.redpacket.entities.RedPacket;
import com.javatest.redpacket.entities.UserRedPacket;
import com.javatest.redpacket.service.UserRedPacketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

/**
 * Created with IntelliJ IDEA.
 * Description:
 *
 * @author lzy
 * @date 2020-08-03 下午5:38
 */
@Service
public class UserRedPacketServiceImpl implements UserRedPacketService {
    // 失败
    private static final int FAILED = 0;
    @Autowired
    private UserRedPacketDao userRedPacketDao;
    @Autowired
    private RedPacketDao redPacketDao;

    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int grabRedPacket(Long redPacketId, Long userId) {
        // 获取红包信息
        final RedPacket redPacket = redPacketDao.getRedPacketForUpdate(redPacketId);
        // 当前小红包库大于0
        if (Objects.nonNull(redPacket) && redPacket.getStock() > 0) {
            redPacketDao.decreaseRedPacket(redPacketId);
            // 生成红包信息
            UserRedPacket userRedPacket = new UserRedPacket();
            userRedPacket.setRedPacketId(redPacketId);
            userRedPacket.setUserId(userId);
            userRedPacket.setAmount(redPacket.getAmount());
            userRedPacket.setNote("抢红包" + redPacketId);
            // 插入抢红包信息
            final int result = userRedPacketDao.grabRedPacket(userRedPacket);
            return result;
        }
        // 失败返回
        return FAILED;
    }

    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int grabRedPacketForVersion(Long redPacketId, Long userId) {
        // 记录开始时间
        long start = System.currentTimeMillis();
        // 无限循环, 等待成功或者时间满100ms退出
        while (true) {
            // 获取循环当前时间
            long end = System.currentTimeMillis();
            // 当时间已经超过100ms, 返回失败
            if ((end - start) > 100) {
                return FAILED;
            }

            // 获取红包信息,注意version值
            final RedPacket redPacket = redPacketDao.getRedPacket(redPacketId);
            // 当前红包库存大于0
            if (Objects.nonNull(redPacket) && redPacket.getStock() > 0) {
                // 再次传入线程保存的version旧值给SQL判断,是否有其他线程修改过数据
                final int update = redPacketDao.decreaseRedPacketForVersion(redPacketId, redPacket.getVersion());
                // 如果没有数据更新，则说明其他线程已经修改过数据，本次抢红包失败
                if (update == 0) {
                    return FAILED;
                }

                // 生成红包信息
                UserRedPacket userRedPacket = new UserRedPacket();
                userRedPacket.setRedPacketId(redPacketId);
                userRedPacket.setUserId(userId);
                userRedPacket.setAmount(redPacket.getAmount());
                userRedPacket.setNote("抢红包" + redPacketId);
                // 插入抢红包信息
                final int result = userRedPacketDao.grabRedPacket(userRedPacket);
                return result;
            } else {
                // 一旦没有库存,立即返回
                return FAILED;
            }
        }
    }
}
